﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ControlCenter.Model;
using ControlCenter.Model.BizEntities;
using ControlCenter.Model.WebApiDto;
using ControlCenter.Operation;
using MingYuanYun.Context.Abstractions;
using MingYuanYun.Exception;
using MingYuanYun.Primitives;

namespace ControlCenter.ApplicationService
{
    /// <summary>
    /// 机器人服务
    /// </summary>
    public class RobotService : ApplicationServiceBase, IRobotService
    {
        private readonly IRobotOperation _robotOperation;
        private readonly IPackageManagementOperation _iPackageManagementOperation;
        private readonly ILogOperation _iLogOperation;

        /// <summary>
        /// 类初始化
        /// </summary>
        /// <param name="context"></param>
        public RobotService(IServiceContext context) : base(context)
        {
            _robotOperation = this.GetService<IRobotOperation>();
            _iPackageManagementOperation = this.GetService<IPackageManagementOperation>();
            _iLogOperation = this.GetService<ILogOperation>();
        }

        /// <summary>
        /// 获取机器人列表
        /// </summary>
        /// <param name="paramDto">请求参数DTO</param>
        /// <returns></returns>
        public async Task<PagedData<RobotInfoDto>> Query(RobotQueryDto paramDto)
        {
            ValidateQuery(paramDto);
            return await _robotOperation.Query(paramDto);
        }

        /// <summary>
        /// 获取机器人列表前参数校验
        /// </summary>
        /// <param name="paramDto"></param>
        private void ValidateQuery(RobotQueryDto paramDto)
        {
            ExceptionAssert.IsNull(paramDto, nameof(paramDto));
            ExceptionAssert.IsTrue(paramDto.PageIndex <=0, $"{nameof(paramDto.PageIndex)} 不能<=0");
            ExceptionAssert.IsTrue(paramDto.PageSize > 10000, $"{nameof(paramDto.PageSize)} 不能>10000");
        }

        /// <summary>
        /// 机器人注册/更新状态，如果数据库不存在机器人信息，则添加
        /// </summary>
        /// <param name="paramDto">请求参数DTO</param>
        /// <returns></returns>
        public async Task<bool> UpdateStatus(RobotUpdateStatusParamDto paramDto)
        {
            //参数校验
            ValidateUpdateStatus(paramDto);

            //更新机器人信息
            RobotInfo robotInfo = new RobotInfo
            {
                RobotId = paramDto.RobotId,
                Name = paramDto.Name,
                Version = paramDto.Version,
                Ip = paramDto.Ip,
                Status = paramDto.Status
            };
            bool isSuccess = await _robotOperation.UpdateOrSave(robotInfo);

            //更新机器人的应用包状态
            if (paramDto.RpId.HasValue && paramDto.RpId != Guid.Empty)
            {
                await _iPackageManagementOperation.UpdateRobotPackagePackageStatus((Guid)paramDto.RpId, (int)PackageStatus.Running, (int)PackageStatus.Stop);
            }

            //写心跳日志
            var heartLogs = new List<HeartLog>();
            heartLogs.Add(new HeartLog{ HeartType=HeartTypeEnum.Robot, ObjectId = paramDto.RobotId, Time = DateTime.Now});
            if (paramDto.RpId.HasValue && paramDto.RpId != Guid.Empty)
            {
                heartLogs.Add(new HeartLog { HeartType = HeartTypeEnum.PackageTask, ObjectId = (Guid)paramDto.RpId, Time = DateTime.Now });
            }
            await _iLogOperation.BatchAddHeartLogs(heartLogs);

            return isSuccess;
        }

        /// <summary>
        /// 机器人注册/更新状态前参数校验
        /// </summary>
        /// <param name="robotInfo"></param>
        private void ValidateUpdateStatus(RobotUpdateStatusParamDto robotInfo)
        {
            ExceptionAssert.IsNull(robotInfo, nameof(robotInfo));

            string errorMsg = "";
            if (robotInfo.RobotId == Guid.Empty)
            {
                errorMsg += $"{nameof(robotInfo.RobotId)} 不能为空；";
            }
            if (string.IsNullOrEmpty(robotInfo.Name))
            {
                errorMsg += $"{nameof(robotInfo.Name)} 不能为空；";
            }
            if (string.IsNullOrEmpty(robotInfo.Ip))
            {
                errorMsg += $"{nameof(robotInfo.Ip)} 不能为空；";
            }
            if (string.IsNullOrEmpty(robotInfo.Version))
            {
                errorMsg += $"{nameof(robotInfo.Version)} 不能为空；";
            }
            if (!string.IsNullOrEmpty(errorMsg))
            {
                throw new BusinessException(errorMsg);
            }
        }

        /// <summary>
        /// 定时刷新机器人运行状态，运行状态的机器人或应用30秒内没有心跳/活动时将其状态更新为离线/未运行
        /// </summary>
        /// <returns></returns>
        public async Task RefreshWorkStatus()
        {
            //读取最近30秒内的心跳记录
            var heartLogs = await _iLogOperation.QueryNearLogs(DateTime.Now.AddSeconds(-30));
            var robotLogs = heartLogs.Where(p => p.HeartType == (int)HeartTypeEnum.Robot);
            var packageLogs = heartLogs.Where(p => p.HeartType == (int)HeartTypeEnum.PackageTask);

            //读取运行状态的机器人和应用
            var robotPackages = await _robotOperation.Query(new RobotQueryDto {Keywords = "", PageSize = 1000, PageIndex = 1});
            var runningRobots =
                robotPackages.Data.Where(
                    p => p.RobotStatus == (int) RobotStatus.Idle || p.RobotStatus == (int) RobotStatus.Execution).Select(p=>p.RobotId).Distinct().ToList();
            var runningPackages = robotPackages.Data.Where(p => p.RpId != Guid.Empty && p.PackageStatus == (int) PackageStatus.Running).Select(p=>p.RpId).Distinct().ToList();

            //心跳记录中不存在机器人或引用时，设置机器人为离线/应用为空闲
            runningRobots.ForEach(robotId =>
            {
                if (!robotLogs.Any(p=>p.ObjectId == robotId))
                {
                    _robotOperation.UpdateRobotStatus(robotId, (int) RobotStatus.OffLine);
                }
            });
            runningPackages.ForEach(rpId =>
            {
                if (!packageLogs.Any(p => p.ObjectId == rpId))
                {
                    _iPackageManagementOperation.UpdateRobotPackagePackageStatus(rpId, (int)PackageStatus.Normal);
                }
                
            });
        }

        /// <summary>
        /// 启用/停用机器人
        /// </summary>
        /// <param name="paramDto"></param>
        /// <returns></returns>
        public async Task<Tuple<bool, string>> SwitchRobot(SwitchRobotRequestDto paramDto)
        {
            //校验参数
            ExceptionAssert.IsNull(paramDto, nameof(paramDto));
            ExceptionAssert.IsTrue(paramDto.RobotId == null || paramDto.RobotId == Guid.Empty, $"{nameof(paramDto.RobotId)} 不能为空");

            //业务校验
            var robot = await _robotOperation.Find((Guid)paramDto.RobotId);
            ExceptionAssert.IsTrue(robot == null, $"机器人不存在, id={(Guid)paramDto.RobotId}");
            if (paramDto.Enable)
            {
                //启用机器人，只有停用状态的可以启用
                ExceptionAssert.IsTrue(robot.Status != RobotStatus.Disabled, "机器人已经是停用状态！");
            }
            else
            {
                //停用机器人, 已经是停用状态的直接返回
                if (robot.Status == RobotStatus.Disabled)
                {
                    return new Tuple<bool, string>(true, "");
                }
            }

            //更新机器人状态
            int newStatus = paramDto.Enable ? (int) RobotStatus.OffLine : (int) RobotStatus.Disabled;
            var updateStatusRet = await _robotOperation.UpdateRobotStatus(robot.RobotId, newStatus);

            return new Tuple<bool, string>(updateStatusRet, updateStatusRet ? "":"数据库操作失败");
        }

        /// <summary>
        /// 删除机器人，运行状态的不能删除（包括机器人和应用包）
        /// </summary>
        /// <param name="robotId"></param>
        /// <returns></returns>
        public async Task<Tuple<bool, string>> DeleteRobot(Guid robotId)
        {
            //参数校验
            ExceptionAssert.IsTrue(robotId == Guid.Empty, $"{nameof(robotId)} 不能为空");

            //业务校验
            var robot = await _robotOperation.Find((Guid)robotId);
            ExceptionAssert.IsTrue(robot == null, $"机器人不存在, id={(Guid)robotId}");
            if (robot.Status == RobotStatus.Execution)
            {
                throw new BusinessException("机器人正在执行任务，不允许删除！");
            }

            //删除机器人和机器人包
            var deleteRobotRet = await _robotOperation.DeleteRobot(robotId);

            return new Tuple<bool, string>(deleteRobotRet, deleteRobotRet ? "": "数据库操作失败");
        }

        /// <summary>
        /// 获取机器人信息
        /// </summary>
        /// <param name="robotId"></param>
        /// <returns></returns>
        public async Task<RobotInfo> GetRobot(Guid robotId)
        {
            //参数校验
            ExceptionAssert.IsTrue(robotId == Guid.Empty, $"{nameof(robotId)} 不能为空");

            return await _robotOperation.Find((Guid)robotId);
        }
    }
}
